package com.z.system.controller;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.z.system.model.Dept;
import com.z.system.service.DeptService;
import com.z.system.utils.R;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;

/**
 * 部门管理控制器
 * 
 * <p>
 * 提供部门信息的增删改查、树形结构展示、状态管理等接口
 * </p>
 * 
 * @author 系统管理员
 * @version 1.0
 * @since 2024-01-01
 */
@RestController
@RequestMapping("/api/dept")
@Tag(name = "部门管理", description = "部门管理相关接口，包括部门信息的增删改查、树形结构展示、状态管理等")
public class DeptController {

    @Autowired
    private DeptService deptService;

    /**
     * 分页查询部门列表
     * 
     * @param pageable 分页参数（页码、每页大小、排序等）
     * @param params   查询参数（可选，支持按部门名称、编码等条件过滤）
     * @return 分页的部门列表数据
     * @apiNote 需要 sys:dept:list 权限
     */
    @GetMapping
    @PreAuthorize("hasAuthority('sys:dept:list')")
    @Operation(summary = "分页查询部门列表", description = "分页查询部门信息列表，支持按条件过滤", responses = {
            @ApiResponse(responseCode = "200", description = "查询成功", content = @Content(schema = @Schema(implementation = Page.class))),
            @ApiResponse(responseCode = "401", description = "未授权访问"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    public R<Page<Dept>> getDepts(@ParameterObject Pageable pageable,
            @Parameter(description = "查询参数", example = "{\"name\": \"技术部\", \"code\": \"TECH\"}") @RequestParam(required = false) Map<String, Object> params) {
        try {
            Page<Dept> depts = deptService.getDepts(pageable, params);
            return R.success(depts);
        } catch (Exception e) {
            return R.error("查询部门列表失败: " + e.getMessage());
        }
    }

    /**
     * 获取部门树形结构
     * 
     * @return 部门树形结构数据，包含父子关系
     * @apiNote 需要 sys:dept:list 权限
     * @example
     *          [
     *          {
     *          "id": "123e4567-e89b-12d3-a456-426614174000",
     *          "name": "总公司",
     *          "children": [
     *          {
     *          "id": "123e4567-e89b-12d3-a456-426614174001",
     *          "name": "技术部",
     *          "children": [...]
     *          }
     *          ]
     *          }
     *          ]
     */
    @GetMapping("/tree")
    @PreAuthorize("isAuthenticated()")
    @Operation(summary = "获取部门树形结构", description = "获取完整的部门树形结构数据，包含父子层级关系", responses = {
            @ApiResponse(responseCode = "200", description = "查询成功", content = @Content(schema = @Schema(implementation = List.class))),
            @ApiResponse(responseCode = "401", description = "未授权访问"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    public R<List<Dept>> getDeptTree() {
        try {
            List<Dept> deptTree = deptService.getDeptTree();
            return R.success(deptTree);
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("获取部门树形结构失败: " + e.getMessage());
        }
    }

    /**
     * 根据父部门ID获取子部门
     */
    @GetMapping("/{parentId}/children")
    @Operation(summary = "获取子部门", description = "根据父部门ID获取所有子部门", responses = @ApiResponse(responseCode = "200", description = "子部门列表", content = @Content(schema = @Schema(implementation = List.class))))
    public R<List<Dept>> getChildDepts(@Parameter(description = "父部门ID", required = true) @PathVariable UUID parentId) {
        try {
            List<Dept> childDepts = deptService.getChildDepts(parentId);
            return R.success(childDepts);
        } catch (Exception e) {
            return R.error("获取子部门失败: " + e.getMessage());
        }
    }

    /**
     * 获取部门详情
     */
    @GetMapping("/{id}")
    @PreAuthorize("hasAuthority('sys:dept:view')")
    @Operation(summary = "获取部门详情", description = "根据部门ID获取部门详情", responses = @ApiResponse(responseCode = "200", description = "部门详情", content = @Content(schema = @Schema(implementation = Dept.class))))
    public R<Dept> getDept(@Parameter(description = "部门ID", required = true) @PathVariable UUID id) {
        try {
            Dept dept = deptService.getDeptById(id);
            if (dept == null) {
                return R.notFound("部门不存在");
            }
            return R.success(dept);
        } catch (Exception e) {
            return R.error("获取部门详情失败: " + e.getMessage());
        }
    }

    /**
     * 创建部门
     * 
     * @param dept 部门信息对象
     * @return 创建成功的部门信息
     * @apiNote 需要 sys:dept:create 权限
     * @throws IllegalArgumentException 当部门名称、编码等必填字段为空或格式不正确时抛出
     * @example
     *          {
     *          "name": "技术部",
     *          "code": "TECH",
     *          "level": 2,
     *          "sort": 1,
     *          "parentId": "123e4567-e89b-12d3-a456-426614174000",
     *          "remark": "负责技术研发"
     *          }
     */
    @PostMapping("/add")
    @PreAuthorize("hasAuthority('sys:dept:create')")
    @Operation(summary = "创建部门", description = "创建新的部门信息，需要验证部门名称和编码的唯一性", responses = {
            @ApiResponse(responseCode = "200", description = "创建成功", content = @Content(schema = @Schema(implementation = Dept.class))),
            @ApiResponse(responseCode = "400", description = "参数验证失败"),
            @ApiResponse(responseCode = "401", description = "未授权访问"),
            @ApiResponse(responseCode = "409", description = "部门名称或编码已存在"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    public R<Dept> createDept(@Parameter(description = "部门信息", required = true) @RequestBody @Valid Dept dept) {
        try {
            // 数据验证
            if (dept.getName() == null || dept.getName().trim().isEmpty()) {
                return R.businessError("部门名称不能为空");
            }
            if (dept.getNameAbbr() == null || dept.getNameAbbr().trim().isEmpty()) {
                dept.setNameAbbr(dept.getName());
            }
            if (dept.getCode() == null || dept.getCode().trim().isEmpty()) {
                return R.businessError("部门编码不能为空");
            }
            if (dept.getSort() == null || dept.getSort() < 0) {
                return R.businessError("排序值不能为空且必须大于等于0");
            }

            // 名称和编码长度验证
            if (dept.getName().length() > 50) {
                return R.businessError("部门名称长度不能超过50个字符");
            }
            if (dept.getNameAbbr().length() > 10) {
                return R.businessError("部门简称长度不能超过10个字符");
            }
            if (dept.getCode().length() > 20) {
                return R.businessError("部门编码长度不能超过20个字符");
            }

            Dept savedDept = deptService.saveDept(dept);
            return R.success("部门创建成功", null);
        } catch (Exception e) {
            return R.error("部门创建失败: " + e.getMessage());
        }
    }

    /**
     * 更新部门
     */
    @PostMapping("/update")
    @PreAuthorize("hasAuthority('sys:dept:update')")
    @Operation(summary = "更新部门", description = "根据部门ID更新部门信息", requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(content = @Content(schema = @Schema(implementation = Dept.class))), responses = @ApiResponse(responseCode = "200", description = "更新成功的部门", content = @Content(schema = @Schema(implementation = Dept.class))))
    public R<Dept> updateDept(@Parameter(description = "部门信息", required = true) @RequestBody @Valid Dept dept) {
        try {

            // 数据验证
            if (dept.getName() == null || dept.getName().trim().isEmpty()) {
                return R.error("部门名称不能为空");
            }
            if (dept.getNameAbbr() == null || dept.getNameAbbr().trim().isEmpty()) {
                return R.error("部门简称不能为空");
            }
            if (dept.getCode() == null || dept.getCode().trim().isEmpty()) {
                return R.error("部门编码不能为空");
            }
            if (dept.getSort() == null || dept.getSort() < 0) {
                return R.error("排序值不能为空且必须大于等于0");
            }

            // 名称和编码长度验证
            if (dept.getName().length() > 50) {
                return R.businessError("部门名称长度不能超过50个字符");
            }
            if (dept.getNameAbbr().length() > 10) {
                return R.businessError("部门简称长度不能超过10个字符");
            }
            if (dept.getCode().length() > 20) {
                return R.businessError("部门编码长度不能超过20个字符");
            }

            Dept updatedDept = deptService.updateDept(dept);
            return R.success("部门更新成功", null);
        } catch (Exception e) {
            return R.error("更新部门失败: " + e.getMessage());
        }
    }

    /**
     * 删除部门
     */
    @PostMapping("/delete/{id}")
    @PreAuthorize("hasAuthority('sys:dept:delete')")
    @Operation(summary = "删除部门", description = "根据部门ID删除部门")
    public R<Void> deleteDept(@Parameter(description = "部门ID", required = true) @PathVariable UUID id) {
        try {
            // 检查部门是否存在
            Dept dept = deptService.getDeptById(id);
            if (dept == null) {
                return R.error("部门不存在");
            }

            // 检查是否为根部门（不允许删除根部门）
            if (dept.getParentId() == null) {
                return R.error("根部门不允许删除");
            }

            deptService.deleteDept(id);
            return R.success("部门删除成功", null);
        } catch (Exception e) {
            return R.error("删除部门失败: " + e.getMessage());
        }
    }

    /**
     * 批量删除部门
     */
    @PostMapping("/batch/delete")
    @PreAuthorize("hasAuthority('sys:dept:delete')")
    @Operation(summary = "批量删除部门", description = "批量删除部门信息", responses = @ApiResponse(responseCode = "200", description = "批量删除成功"))
    public R<Void> deleteDepts(@Parameter(description = "部门ID列表", required = true) @RequestBody Set<UUID> ids) {
        try {
            // 参数非空校验
            if (ids == null || ids.isEmpty()) {
                return R.error("部门ID列表不能为空");
            }

            // 检查ID数量限制（防止一次性删除过多）
            if (ids.size() > 100) {
                return R.error("一次性最多删除100个部门");
            }

            // 检查是否包含根部门
            for (UUID id : ids) {
                Dept dept = deptService.getDeptById(id);
                if (dept == null) {
                    return R.error("部门ID " + id + " 不存在");
                }
                if (dept.getParentId() == null) {
                    return R.error("包含根部门，不允许删除");
                }
            }

            deptService.deleteDepts(ids);
            return R.success("批量删除部门成功", null);
        } catch (Exception e) {
            return R.error("批量删除部门失败: " + e.getMessage());
        }
    }

    /**
     * 启用/禁用部门
     */
    @PutMapping("/{id}/status")
    @PreAuthorize("hasAuthority('sys:dept:update')")
    @Operation(summary = "启用/禁用部门", description = "更新部门的启用状态")
    public R<Void> updateDeptStatus(@Parameter(description = "部门ID", required = true) @PathVariable UUID id,
            @Parameter(description = "启用状态，true启用，false禁用", required = true) @RequestParam String enabled) {
        try {
            if (enabled == null || (!"true".equals(enabled) && !"false".equals(enabled))) {
                return R.error("启用状态参数无效，必须为true或false");
            }

            // 检查部门是否存在
            Dept dept = deptService.getDeptById(id);
            if (dept == null) {
                return R.error("部门不存在");
            }

            // 检查是否尝试更新为相同状态
            if (enabled.equals(dept.getStatus())) {
                return R.error("部门状态未发生变化");
            }

            deptService.updateDeptStatus(id, enabled);
            return R.success("部门状态更新成功", null);
        } catch (Exception e) {
            return R.error("更新部门状态失败: " + e.getMessage());
        }
    }

    /**
     * 检查部门是否有子部门
     */
    @GetMapping("/{id}/has-children")
    @Operation(summary = "检查部门是否有子部门", description = "检查指定部门是否包含子部门", responses = @ApiResponse(responseCode = "200", description = "是否有子部门", content = @Content(schema = @Schema(implementation = Boolean.class))))
    public R<Boolean> hasChildDept(@Parameter(description = "部门ID", required = true) @PathVariable UUID id) {
        try {
            boolean hasChildren = deptService.hasChildDept(id);
            return R.success(hasChildren);
        } catch (Exception e) {
            return R.error("检查子部门失败: " + e.getMessage());
        }
    }

    /**
     * 检查部门是否有用户
     */
    @GetMapping("/{id}/has-users")
    @Operation(summary = "检查部门是否有用户", description = "检查指定部门是否包含用户", responses = @ApiResponse(responseCode = "200", description = "是否有用户", content = @Content(schema = @Schema(implementation = Boolean.class))))
    public R<Boolean> hasUserInDept(@Parameter(description = "部门ID", required = true) @PathVariable UUID id) {
        try {
            boolean hasUsers = deptService.hasUserInDept(id);
            return R.success(hasUsers);
        } catch (Exception e) {
            return R.error("检查部门用户失败: " + e.getMessage());
        }
    }

    /**
     * 获取部门统计信息
     * 
     * @return 部门统计信息，包括总数、启用数量、禁用数量等
     * @apiNote 需要 sys:dept:list 权限
     * @example
     *          {
     *          "totalDepts": 50,
     *          "enabledDepts": 45,
     *          "disabledDepts": 5,
     *          "deptsWithChildren": 10,
     *          "deptsWithUsers": 30
     *          }
     */
    @GetMapping("/statistics")
    @PreAuthorize("hasAuthority('sys:dept:list')")
    @Operation(summary = "获取部门统计信息", description = "获取部门相关的统计信息，包括总数、启用状态、子部门数量等", responses = {
            @ApiResponse(responseCode = "200", description = "统计信息", content = @Content(schema = @Schema(implementation = Map.class))),
            @ApiResponse(responseCode = "401", description = "未授权访问"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    public R<Map<String, Object>> getDeptStatistics() {
        try {
            Map<String, Object> statistics = deptService.getDeptStatistics();
            return R.success(statistics);
        } catch (Exception e) {
            return R.error("获取部门统计信息失败: " + e.getMessage());
        }
    }

    /**
     * 根据部门名称模糊查询部门列表
     * 
     * @param name 部门名称（支持模糊查询）
     * @return 匹配的部门列表
     * @apiNote 需要 sys:dept:list 权限
     */
    @GetMapping("/search")
    @PreAuthorize("hasAuthority('sys:dept:list')")
    @Operation(summary = "根据名称搜索部门", description = "根据部门名称进行模糊查询，返回匹配的部门列表", responses = {
            @ApiResponse(responseCode = "200", description = "部门列表", content = @Content(schema = @Schema(implementation = List.class))),
            @ApiResponse(responseCode = "401", description = "未授权访问"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    public R<List<Dept>> searchDeptsByName(
            @Parameter(description = "部门名称", required = false) @RequestParam(required = false) String name) {
        try {
            List<Dept> depts = deptService.searchDeptsByName(name);
            return R.success(depts);
        } catch (Exception e) {
            return R.error("搜索部门失败: " + e.getMessage());
        }
    }

    /**
     * 获取部门用户数量统计
     * 
     * @return 部门ID到用户数量的映射关系
     * @apiNote 需要 sys:dept:list 权限
     * @example
     *          {
     *          "123e4567-e89b-12d3-a456-426614174000": 15,
     *          "123e4567-e89b-12d3-a456-426614174001": 8
     *          }
     */
    @GetMapping("/user-counts")
    @PreAuthorize("hasAuthority('sys:dept:list')")
    @Operation(summary = "获取部门用户数量统计", description = "获取每个部门的用户数量统计信息", responses = {
            @ApiResponse(responseCode = "200", description = "用户数量统计", content = @Content(schema = @Schema(implementation = Map.class))),
            @ApiResponse(responseCode = "401", description = "未授权访问"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    public R<Map<UUID, Long>> getDeptUserCounts() {
        try {
            Map<UUID, Long> userCounts = deptService.getDeptUserCounts();
            return R.success(userCounts);
        } catch (Exception e) {
            return R.error("获取部门用户数量统计失败: " + e.getMessage());
        }
    }

    /**
     * 获取启用状态的部门列表
     * 
     * @return 所有启用状态的部门列表
     * @apiNote 需要 sys:dept:list 权限
     */
    @GetMapping("/enabled")
    @PreAuthorize("hasAuthority('sys:dept:list')")
    @Operation(summary = "获取启用状态的部门列表", description = "获取所有启用状态的部门信息", responses = {
            @ApiResponse(responseCode = "200", description = "启用部门列表", content = @Content(schema = @Schema(implementation = List.class))),
            @ApiResponse(responseCode = "401", description = "未授权访问"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误")
    })
    public R<List<Dept>> getEnabledDepts() {
        try {
            List<Dept> enabledDepts = deptService.getEnabledDepts();
            return R.success(enabledDepts);
        } catch (Exception e) {
            return R.error("获取启用部门列表失败: " + e.getMessage());
        }
    }
}